package com.parkwalk.xxx.ui.security;

import java.io.File;
import java.io.FileInputStream;
import java.io.UnsupportedEncodingException;
import java.security.NoSuchAlgorithmException;
import java.util.HashMap;
import java.util.Map;
import java.util.zip.Adler32;
import java.util.zip.CRC32;
import java.util.zip.Checksum;

public class Checker {
    public static final Map<String, String> map = new HashMap<String, String>();

    public static final String[] SUPPORTED_TYPES = {"CRC-32", "CRC-16",
            "CRC-16/CCITT", "Adler32"};

    static {
        map.put("CRC-32", CRC32.class.getCanonicalName());
        map.put("CRC-16", CRC16.class.getCanonicalName());
        map.put("CRC-16/CCITT", CRC16_CCITT.class.getCanonicalName());
        map.put("Adler32", Adler32.class.getCanonicalName());
    }

    public static long compute(byte[] bytes, String type) {
        Checksum check = getChecksum(type);
        check.update(bytes, 0, bytes.length);
        return check.getValue();
    }

    public static long compute(File file, String type) {
        FileInputStream fis = null;
        try {
            Checksum check = getChecksum(type);

            if (check != null) {
                fis = new FileInputStream(file);
                byte[] buffer = new byte[1048576];

                for (int bytesRead = 0; (bytesRead = fis.read(buffer)) != -1; ) {
                    check.update(buffer, 0, bytesRead);
                }

                long l = check.getValue();
                return l;
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (fis != null) {
                    fis.close();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        try {
            if (fis != null) {
                fis.close();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        return 0L;
    }

    public static long compute(String str, String type) {
        return compute(str.getBytes(), type);
    }

    public static long compute(String str, String type, String charsetName) {
        try {
            return compute(str.getBytes(charsetName), type);
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }

        return 0L;
    }

    public static String computeToHex(byte[] bytes, String type) {
        long value = compute(bytes, type);
        return value == 0L ? null : longToHex(value);
    }

    public static String computeToHex(File file, String type) {
        long value = compute(file, type);
        return value == 0L ? null : longToHex(value);
    }

    public static String computeToHex(String str, String type) {
        long value = compute(str, type);
        return value == 0L ? null : longToHex(value);
    }

    public static String computeToHex(String str, String type,
                                      String charsetName) {
        long value = compute(str, type, charsetName);
        return value == 0L ? null : longToHex(value);
    }

    private static Checksum getChecksum(String type) {
        String name = (String) map.get(type);

        if (name == null) {
            try {
                throw new NoSuchAlgorithmException("Unsupported this type:"
                        + type);
            } catch (NoSuchAlgorithmException e) {
                e.printStackTrace();
            }
        } else {
            try {
                Class<?> clazz = Class.forName(name);
                return (Checksum) clazz.newInstance();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        return null;
    }

    public static String[] getSupportedTypes() {
        return SUPPORTED_TYPES;
    }

    private static String longToHex(long value) {
        String hex = Long.toHexString(value);
        return '0' + hex;
    }
}